/**
 * 
 */
package com.vision.core.cl;

import net.customware.gwt.dispatch.shared.DispatchException;

import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.InvocationException;
import com.google.gwt.user.client.rpc.StatusCodeException;
import com.sencha.gxt.widget.core.client.Component;
import com.vision.core.cl.ui.Maskable;
import com.vision.core.cl.ui.Notifications;
import com.vision.core.cm.exception.RpcException;

/**
 * @author Mark
 *
 */
public class Callback<T> implements AsyncCallback<T> {
	
	/**
	 * A reference to a masked UI component. This component
	 * will be unmasked upon receiving of server response
	 * or if the server call fails.
	 */
	private Component maskedComponent;
	private Maskable maskable;
	
	public Callback() {
		
	}
	
	public Callback(Component maskedComponent) {
		this.maskedComponent = maskedComponent;
	}
	
	public Callback(Maskable maskable) {
		this.maskable = maskable;
	}
	
	public static void onException(Throwable t) {
		// Exceptions thrown by the actual service
		if (t instanceof RpcException) {
			Notifications.rpcError((RpcException) t);
		}
		// For GWT-Dispatch invocations
		else if (t instanceof DispatchException) {
			Notifications.rpcError((DispatchException) t);
		}
		else if (t instanceof StatusCodeException) {
			StatusCodeException sce = (StatusCodeException) t;
			int code = sce.getStatusCode();
			if (code == 0) { // No Connection to Server
				Notifications.error("No Connection", "Unable to establish connection to server. Please check your connection.");
			} else if (code == 500) { // Internal Server Error
				Notifications.error("Request Failed", "An error in the server was encountered. Please contact tech support.");
			} else {
				Notifications.error("Request Failed", "Server was unable to process your request. Code: " + code);
			}
		}
		else if (t instanceof IncompatibleRemoteServiceException) {
			Notifications.error("Outdated Application", "Your version of the application is outdated. Page will refresh in 3 seconds. If it doesn't, manually refresh the page.");
			Timer timer = new Timer() {
				@Override
				public void run() {
					Notifications.clearMessage();
					Window.Location.reload();
				}
			};
			timer.schedule(3000);
		}
		// When user session has expired
		else if (t instanceof InvocationException) {
			String message = t.getMessage();
			if (message != null && message.contains("j_spring_security_check")) {
				Window.Location.assign("login.jsp");
				return;
			}
			Notifications.unexpectedError(t);
		}
		// All other forms of Exception
		else {
			Notifications.unexpectedError(t);
		}
	}

	@Override
	public void onFailure(Throwable t) {
		onException(t);
		
		try {
			handleFailure(t);
		} catch (Exception e) {
			Notifications.unexpectedError(e);
		} finally {
			unmask();
		}
	}

	@Override
	public void onSuccess(T result) {
		try {
			handleSuccess(result);
		} catch (Exception e) {
			Notifications.unexpectedError(e);
		} finally {
			unmask();
		}
	}
	
	/**
	 * Called to handle failure of an RPC call.
	 * @param t
	 */
	protected void handleFailure(Throwable t) {
	}
	
	/**
	 * Called to handle successful RPC call.
	 * @param result
	 */
	protected void handleSuccess(T result) {
		
	}
	
	protected void unmask() {
		if (maskedComponent != null)
			maskedComponent.unmask();
		
		if (maskable != null)
			maskable.unmask();
	}

}
